import BpmnModeler from "@/module/main/other/BpmnTestView/BpmnModeler";
import {Component, ComponentProps, Computed, Hook, Mut, VueComponent} from "vue3-oop";
import {NCheckbox, NForm, NFormItemGi, NGrid, NInput, NSelect, NSpace, NRadioGroup, NRadio} from "naive-ui";

interface IProps {
  bpmnModeler: BpmnModeler,
  elementId: string,
  elementName: string,
  elementType: string
}
@Component()
export default class Index extends VueComponent<IProps> {
  static defaultProps: ComponentProps<IProps> = {
    bpmnModeler: {default: {} as any},
    elementId: {default: ''},
    elementName: {default: ''},
    elementType: {default: ''}
  }

  public static tabKey = "INSTANCES"
  public static tabName = "多实例"

  @Mut() state = {
    /** 回路特性 */
    loopType: '',
    /** 可选回路特性 */
    loopTypes: [
      {value: 'No', label: '无'},
      {value: 'Loop', label: '循环'},
      {value: 'Multi', label: '多实例'},
    ],
    loopProps: {
      /** 顺序多实例 */
      isSequential: false,
      /** 循环集合 */
      collection: '',
      /** 循环基数 */
      loopCardinality: '',
      /** 元素变量 */
      elementVariable: '',
      /** 完成条件 */
      completionCondition: '',
      /** 异步前 */
      asyncBefore: false,
      /** 异步后 */
      asyncAfter: false,
      /** 排除 */
      exclusive: false,
      /** 重试周期 */
      retryTimes: '',
    }
  }
  @Computed() get isAsync(){return (this.state.loopProps.asyncBefore||this.state.loopProps.asyncAfter)}

  private initLoopProps=()=>{
    this.state.loopProps = {
      isSequential: false,
      collection: '',
      loopCardinality: '',
      elementVariable: '',
      completionCondition: '',
      asyncBefore: false,
      asyncAfter: false,
      exclusive: false,
      retryTimes: '',
    };
  }

  private loadPropsFromElement=()=>{
    const element = this.props.bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    if(!loopCharacteristics){
      this.state.loopType = 'No';
    }else if(loopCharacteristics.$type==="bpmn:StandardLoopCharacteristics") {
      this.state.loopType = 'Loop';
    }else if(loopCharacteristics.$type==='bpmn:MultiInstanceLoopCharacteristics'){
      this.state.loopType = 'Multi';
      this.state.loopProps.isSequential = loopCharacteristics.isSequential;
      this.state.loopProps.collection = loopCharacteristics.collection;
      this.state.loopProps.elementVariable = loopCharacteristics.elementVariable;
      this.state.loopProps.completionCondition = loopCharacteristics.completionCondition?.body;
      this.state.loopProps.loopCardinality = loopCharacteristics.loopCardinality?.body;
      this.state.loopProps.asyncBefore = loopCharacteristics.asyncBefore;
      this.state.loopProps.asyncAfter = loopCharacteristics.asyncAfter;
      this.state.loopProps.exclusive = loopCharacteristics.exclusive;
      loopCharacteristics.extensionElements?.values.forEach((item:any)=>{
        if(item.$type==='flowable:FailedJobRetryTimeCycle'){
          this.state.loopProps.retryTimes = item.body;
        }
      })
    }
  }

  private updateLoopType=(value:any)=>{
    this.state.loopType = value;
    this.initLoopProps();

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    let loopCharacteristics = null;
    if(this.state.loopType==='Loop'){
      loopCharacteristics = bpmnModeler.getModdle().create("bpmn:StandardLoopCharacteristics");
    }else if(this.state.loopType==='Multi'){
      loopCharacteristics = bpmnModeler.getModdle().create("bpmn:MultiInstanceLoopCharacteristics");
    }
    bpmnModeler.getModeling().updateProperties(element, {loopCharacteristics});
  }

  private updateIsSequential=(value:boolean)=>{
    this.state.loopProps.isSequential = value;

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, {
      isSequential: this.state.loopProps.isSequential
    });
  }

  private updateCollection=(value:any)=>{
    this.state.loopProps.collection = value;

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, {
      collection: this.state.loopProps.collection
    });
  }

  private updateElementVariable=(value:any)=>{
    this.state.loopProps.elementVariable = value;

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, {
      elementVariable: this.state.loopProps.elementVariable
    });
  }

  private updateLoopCardinality=(value:any)=>{
    this.state.loopProps.loopCardinality = value;

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;

    let loopCardinality = null;
    if (this.state.loopProps.loopCardinality?.length) {
      loopCardinality = bpmnModeler.getModdle().create("bpmn:FormalExpression", { body: this.state.loopProps.loopCardinality });
    }
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, { loopCardinality });

  }

  private updateCompletionCondition=(value:any)=>{
    this.state.loopProps.completionCondition = value;

    const {bpmnModeler} = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;

    let completionCondition = null;
    if(this.state.loopProps.completionCondition?.length){
      completionCondition = bpmnModeler.getModdle().create("bpmn:FormalExpression", { body: this.state.loopProps.completionCondition });
    }
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, { completionCondition });
  }

  private updateAsyncBefore=(value:boolean)=>{
    this.state.loopProps.asyncBefore=value;
    this.updateExclusive(this.state.loopProps.exclusive);
    this.updateRetryTimes(this.state.loopProps.retryTimes);

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, {
      asyncBefore: this.state.loopProps.asyncBefore
    });
  }

  private updateAsyncAfter=(value:boolean)=>{
    this.state.loopProps.asyncAfter=value;
    this.updateExclusive(this.state.loopProps.exclusive);
    this.updateRetryTimes(this.state.loopProps.retryTimes);

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, {
      asyncAfter: this.state.loopProps.asyncAfter
    });
  }

  private updateExclusive = (value:boolean)=>{
    this.state.loopProps.exclusive = this.isAsync && value;

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, {
      exclusive: this.state.loopProps.exclusive
    });
  }

  private updateRetryTimes=(value:any)=>{
    this.state.loopProps.retryTimes = this.isAsync?value:'';

    const { bpmnModeler } = this.props;
    const element = bpmnModeler.getSelectedElement();
    const { businessObject } = element;
    const { loopCharacteristics } = businessObject;

    const extensionElements = bpmnModeler.getModdle().create("bpmn:ExtensionElements", {
      values: [bpmnModeler.getModdle().create('flowable:FailedJobRetryTimeCycle', {body: this.state.loopProps.retryTimes })]
    });
    bpmnModeler.getModeling().updateModdleProperties(element, loopCharacteristics, { extensionElements });

  }

  render(){
    this.loadPropsFromElement();
    return(
      <NForm labelPlacement="left" labelWidth={100}>
        <NGrid cols={2} xGap={20}>
          <NFormItemGi label="回路特性">
            <NRadioGroup value={this.state.loopType} onUpdateValue={this.updateLoopType}>
              <NSpace>
                {this.state.loopTypes.map((item)=><NRadio value={item.value}>{item.label}</NRadio>)}
                {this.state.loopType==='Multi' && <NCheckbox checked={this.state.loopProps.isSequential} onUpdateChecked={this.updateIsSequential}>顺序</NCheckbox> }
              </NSpace>
            </NRadioGroup>
          </NFormItemGi>
          { this.state.loopType==='Multi' && <>
            <NFormItemGi label="循环集合"><NInput value={this.state.loopProps.collection} onUpdateValue={this.updateCollection} /></NFormItemGi>
            <NFormItemGi label="循环基数"><NInput value={this.state.loopProps.loopCardinality} onUpdateValue={this.updateLoopCardinality} /></NFormItemGi>
            <NFormItemGi label="元素变量"><NInput value={this.state.loopProps.elementVariable} onUpdateValue={this.updateElementVariable} /></NFormItemGi>
            <NFormItemGi label="完成条件"><NInput value={this.state.loopProps.completionCondition} onUpdateValue={this.updateCompletionCondition} /></NFormItemGi>
            <NFormItemGi label="异步状态">
              <NSpace>
                <NCheckbox checked={this.state.loopProps.asyncBefore} onUpdateChecked={this.updateAsyncBefore}>异步前</NCheckbox>
                <NCheckbox checked={this.state.loopProps.asyncAfter} onUpdateChecked={this.updateAsyncAfter}>异步后</NCheckbox>
                { this.isAsync && <NCheckbox checked={this.state.loopProps.exclusive} onUpdateChecked={this.updateExclusive}>排除</NCheckbox>}
              </NSpace>
            </NFormItemGi>
            { this.isAsync && <NFormItemGi label="重试周期"><NInput value={this.state.loopProps.retryTimes} onUpdateValue={this.updateRetryTimes} /></NFormItemGi> }
          </>}
        </NGrid>
      </NForm>
    )
  }
}